package eu.sudparis.it.opp.demo;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import eu.sudparis.it.opp.Community;
import eu.sudparis.it.opp.Interceptor;
import eu.sudparis.it.opp.Node;
import eu.sudparis.it.opp.TimeSeries;
import eu.sudparis.it.opp.ex.SocialTags;
import eu.sudparis.it.opp.graph.Clique;
import eu.sudparis.it.opp.graph.Snapshot;

public class GraphAnalysis implements Interceptor {
	private boolean init = false;
	public PrintStream clique_log;
	public PrintStream edges;
	public PrintStream clique_count;
	public PrintStream community_log;
	public String path;
	public List<Clique> detected = new ArrayList<Clique>();
	public static DateFormat dateformat = new SimpleDateFormat("yyyy-MMM-dd-HH:mm");
	public HashMap<String, HashMap<Long, Integer>> tracking = new HashMap<String, HashMap<Long, Integer>>();

	@Override
	public void init(TimeSeries g) {
		// TODO Auto-generated method stub
		try {
			this.edges = new PrintStream(path + "//edges.txt");
			this.clique_log = new PrintStream(path + "//log.txt");
			this.clique_count = new PrintStream(path + "//count.txt");
			community_log = new PrintStream(path + "//community.txt");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void before(TimeSeries g) {
		// TODO Auto-generated method stub

	}

	@Override
	public void after(TimeSeries g) {
		// TODO Auto-generated method stub

		if (this.init == false) {
			Collection<Node> allnds = g.graph.graph.values();
			for (Node nd : allnds) {
				DNode dnd = ((DNode) (nd.chain_of_responsibility));
				if (dnd.self == null)
					dnd.initial();
			}
			this.init = true;
		} else {
			if (g.currentTime % 60 == 0) {
				List<Node> nds = new ArrayList<Node>(g.graph.graph.values());
				doAnalysis(nds, g);
			}
		}

	}

	@Override
	public void fini(TimeSeries g) {
		// TODO Auto-generated method stub
		try {
			for (Clique sub : detected) {
				if(sub.last_observed-sub.first_observed<Community.cont_index)
					continue;
				HashMap<String, HashMap<Long, Integer>> impact = this
						.impactEstimation(sub);
				this.mergeTo(tracking, impact);
				community_log.println(sub);
			}
			this.outputTracking();
			community_log.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void outputTracking() throws FileNotFoundException {
		for (String fname : this.tracking.keySet()) {
			HashMap<Long, Integer> impact = tracking.get(fname);
			PrintStream ps = new PrintStream(path + "//" + fname + ".txt");
			List<Long> times = new ArrayList<Long>(impact.keySet());
			Collections.sort(times);
			for (long time : times) {
				ps.println(toDateSinceInfoCom(time) + "," + impact.get(time));
			}
			ps.close();
		}
	}

	public HashMap<String, HashMap<Long, Integer>> impactEstimation(Clique sub) {
		HashMap<String, HashMap<Long, Integer>> results = new HashMap<String, HashMap<Long, Integer>>();
		for (String sn : sub.shared_interests.keySet()) {
			for (int interest : sub.shared_interests.get(sn)) {
				HashMap<Long, Integer> maps = new HashMap<Long, Integer>();
				results.put(sn + interest, maps);
				for (long i = sub.first_observed; i <= sub.last_observed; i+=Community.cont_index) {
					maps.put(i, 1);
				}
			}
		}
		return results;
	}

	public void mergeTo(HashMap<String, HashMap<Long, Integer>> map1,
			HashMap<String, HashMap<Long, Integer>> map2) {
		for (String key : map2.keySet()) {
			if (!map1.containsKey(key)) {
				map1.put(key, new HashMap<Long, Integer>(map2.get(key)));
			} else {
				HashMap<Long, Integer> list1 = map1.get(key);
				HashMap<Long, Integer> list2 = map2.get(key);
				for (long time : list2.keySet()) {
					if (!list1.containsKey(time)) {
						list1.put(time, list2.get(time));
					} else {
						list1.put(time, list1.get(time) + list2.get(time));
					}
				}
			}
		}
	}

	public static String toDateSinceInfoCom(long time) {
		Date date = new Date();
		date.setYear(106);
		date.setMonth(3);
		date.setDate(23);
		date.setHours(17);
		date.setMinutes(1);
		date.setSeconds(0);
		time = date.getTime() + time * 1000;
		date.setTime(time);

		return dateformat.format(date);
	}

	public static String toDate(long time) {
		Date date = new Date(time*1000);
		return dateformat.format(date);
	}

	
	public void doAnalysis(List<Node> nds, TimeSeries g) {
		// ps.println(nds.size());
		Snapshot<Node> sp = new Snapshot<Node>(nds);
		edges.println(toDateSinceInfoCom(g.currentTime) + "," + sp.edges.size());
		// ps.println(sp.edges.size());
		List<List<Node>> ndss = sp.getCliques();
		clique_count.println(toDateSinceInfoCom(g.currentTime) + "," + ndss.size());
		for (List<Node> ndt : ndss) {
			clique_log.println("************" + toDateSinceInfoCom(g.currentTime)
					+ "***************");
			clique_log.println(ndt);
			Clique clique = new Clique(ndt, g);
			DNode dnd = ((DNode) (ndt.get(0).chain_of_responsibility));
			for (String name : dnd.self.profile.keySet()) {
				HashMap<Integer, Integer> results = SocialTags.entropyEstimation(
						ndt, name);
				double entropy = SocialTags.minimalEntropy(results, ndt.size());
				if (entropy == 0) {
					clique_log.println("Feature:\t" + name);
					clique_log.println("Dist:\t" + results);
					for (int interest : results.keySet()) {
						if (results.get(interest) == ndt.size()) {
							clique.addShared_interests(name, interest);
						}
					}
				}
			}
			clique.first_observed = g.currentTime;
			clique.last_observed = g.currentTime;
			if (clique.shared_interests.size() > 0
					&& !detected.contains(clique)) {
				detected.add(clique);
			}
		}
	}

}
